package com.ssi.core.framework.dao.impl;

import java.io.Serializable;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.springframework.orm.ibatis.SqlMapClientCallback;
import org.springframework.orm.ibatis.support.SqlMapClientDaoSupport;

import com.ibatis.sqlmap.client.SqlMapClient;
import com.ibatis.sqlmap.client.SqlMapExecutor;
import com.ibatis.sqlmap.engine.execution.SqlExecutor;
import com.ibatis.sqlmap.engine.impl.ExtendedSqlMapClient;
import com.ibatis.sqlmap.engine.impl.SqlMapClientImpl;
import com.ibatis.sqlmap.engine.mapping.sql.stat.StaticSql;
import com.ibatis.sqlmap.engine.mapping.statement.MappedStatement;
import com.ssi.core.framework.dao.GenericDao;
import com.ssi.core.framework.page.PageModel;
import com.ssi.core.framework.web.PageInfoUtil;
import com.ssi.core.util.ReflectUtil;

/**
 * 类说明：BaseDao实现�?
 * 
 * @创建时间 Jan 8, 2011 4:01:31 PM
 * @创建人： Farley
 * @邮箱：kfy0521@163.com
 */

public abstract class IbatisGenericDao<E, PK extends Serializable> extends
		SqlMapClientDaoSupport implements GenericDao<E, PK> {

	public static final String SQLID_INSERT = "insert";

	public static final String SQLID_UPDATE = "update";

	public static final String SQLID_DELETE = "delete";

	public static final String SQLID_SELECT = "select";

	public static final String SQLID_GETALL = "getAll";

	public static final String SQLID_SELECT_PK = "selectPk";

	public static final String SQLID_COUNT = "count";

	protected String sqlmapNamespace = "";

	private SqlExecutor sqlExecutor;

	public SqlExecutor getSqlExecutor() {

		return sqlExecutor;
	}

	public void setSqlExecutor(SqlExecutor sqlExecutor) {
		this.sqlExecutor = sqlExecutor;
	}

	public void setEnableLimit(boolean enableLimit) {
		if (sqlExecutor instanceof LimitSqlExecutor) {

			((LimitSqlExecutor) sqlExecutor).setEnableLimit(enableLimit);
		}
	}

	public void initialize() throws Exception {
		if (sqlExecutor != null) {
			SqlMapClient sqlMapClient = getSqlMapClientTemplate()
					.getSqlMapClient();
			if (sqlMapClient instanceof ExtendedSqlMapClient) {
				ReflectUtil.setFieldValue(((ExtendedSqlMapClient) sqlMapClient)
						.getDelegate(), "sqlExecutor", SqlExecutor.class,
						sqlExecutor);
			}
		}
	}

	protected String getExecuteSql(String statementId) {
		SqlMapClientImpl sqlmap = (SqlMapClientImpl) this.getSqlMapClient();
		MappedStatement stmt = sqlmap.getMappedStatement(sqlmapNamespace
				+ statementId);
		StaticSql stmtSql = (StaticSql) stmt.getSql();
		String sql = stmtSql.getSql(null, null);

		return sql;
	}

	/**
	 * sqlmapNamespace，对应sqlmap.xml中的命名空间
	 * 
	 * @return
	 */
	public String getSqlmapNamespace() {

		return sqlmapNamespace.substring(0, sqlmapNamespace.length()-1);
	}

	/**
	 * sqlmapNamespace的设置方法，可以用于spring注入
	 * 
	 * @param sqlmapNamespace
	 */
	public void setSqlmapNamespace(String sqlmapNamespace) {

		this.sqlmapNamespace = sqlmapNamespace + ".";
	}

	public void batchDelete(final List<PK> list) {
		SqlMapClientCallback callback = new SqlMapClientCallback() {
			public Object doInSqlMapClient(SqlMapExecutor executor)
					throws SQLException {
				executor.startBatch();
				for (PK member : list) {
					executor.delete(sqlmapNamespace + SQLID_DELETE,
							member);
				}
				executor.executeBatch();
				return null;
			}
		};

		this.getSqlMapClientTemplate().execute(callback);
	}

	public void batchInsert(final List<E> list) {
		SqlMapClientCallback callback = new SqlMapClientCallback() {
			public Object doInSqlMapClient(SqlMapExecutor executor)
					throws SQLException {
				executor.startBatch();
				for (E member : list) {
					executor.insert(sqlmapNamespace + SQLID_INSERT,
							member);
				}
				executor.executeBatch();
				return null;
			}
		};

		this.getSqlMapClientTemplate().execute(callback);
	}

	public void batchUpdate(final List<E> list) {
		SqlMapClientCallback callback = new SqlMapClientCallback() {
			public Object doInSqlMapClient(SqlMapExecutor executor)
					throws SQLException {
				executor.startBatch();
				for (E member : list) {
					executor.update(sqlmapNamespace + SQLID_UPDATE,
							member);
				}
				executor.executeBatch();
				return null;
			}
		};

		this.getSqlMapClientTemplate().execute(callback);
	}

	public int count() {
		Integer count = (Integer) getSqlMapClientTemplate().queryForObject(
				sqlmapNamespace + SQLID_COUNT);

		return count.intValue();
	}

	public int delete(PK primaryKey) {
		int rows = getSqlMapClientTemplate().delete(
				sqlmapNamespace + SQLID_DELETE, primaryKey);

		return rows;
	}

	public E get(PK primaryKey) {

		return (E) getSqlMapClientTemplate().queryForObject(
				sqlmapNamespace + SQLID_SELECT_PK, primaryKey);
	}

	public void insert(E entity) {

		getSqlMapClientTemplate().insert(sqlmapNamespace + SQLID_INSERT,
				entity);
	}

	public List<E> getAll() {

		return getAll(null);
	}
	
	@SuppressWarnings("unchecked")
	public List<E> getAll(Map<String, Object> params){ 

		return getSqlMapClientTemplate().queryForList(
				sqlmapNamespace + SQLID_GETALL,params);
	}

	public int update(E entity) {

		return getSqlMapClientTemplate().update(
				sqlmapNamespace + SQLID_UPDATE, entity);
	}

	public List<E> queryForList(String statementId, Object parameters) {

		return getSqlMapClientTemplate().queryForList(
				sqlmapNamespace + statementId, parameters);
	}

	public List<E> queryForList(String statementId, Object parameters,
			PageModel page) {
		int recordCnt = (Integer) getSqlMapClientTemplate().queryForObject(
				sqlmapNamespace + statementId + "_" + SQLID_COUNT,
				parameters);
		page.setTotalRecords(recordCnt);
		PageInfoUtil.processPage(page);
		return getSqlMapClientTemplate().queryForList(
				sqlmapNamespace + statementId, parameters,
				page.getStartRowPosition(), page.getPageSize());
	}

	public List<E> queryForList(String statementId) {
		return getSqlMapClientTemplate().queryForList(
				sqlmapNamespace + statementId);
	}

	public List<E> queryForList(String statementId, PageModel page) {
		int recordCnt = (Integer) getSqlMapClientTemplate().queryForObject(
				sqlmapNamespace + statementId + "_" + SQLID_COUNT);
		page.setTotalRecords(recordCnt);
		PageInfoUtil.processPage(page);
		return getSqlMapClientTemplate().queryForList(
				sqlmapNamespace + statementId,
				page.getStartRowPosition(), page.getPageSize());
	}

	public List<E> queryForList(String statementId, String sql) {
		if (StringUtils.isEmpty(sql))
			return this.getSqlMapClientTemplate().queryForList(
					sqlmapNamespace + statementId, null);
		else
			return this.getSqlMapClientTemplate().queryForList(
					sqlmapNamespace + statementId, sql);
	}

	public List<E> queryForList(String statementId, Map map) {
		if (map == null)
			return this.getSqlMapClientTemplate().queryForList(
					sqlmapNamespace + statementId, null);
		else {
			return this.getSqlMapClientTemplate().queryForList(
					sqlmapNamespace + statementId, map);
		}

	}

	public E queryForObject(String statementId, Object parameters) {

		return (E) getSqlMapClientTemplate().queryForObject(
				sqlmapNamespace + statementId, parameters);
	}

	public void update(String statementId, Object parameters) {

		getSqlMapClientTemplate().update(sqlmapNamespace + statementId,
				parameters);
	}

	public void delete(String statementId, Object parameters) {

		getSqlMapClientTemplate().delete(sqlmapNamespace + statementId,
				parameters);
	}

	public void delete(Object parameters) {

		getSqlMapClientTemplate().delete(sqlmapNamespace + SQLID_DELETE,
				parameters);
	}

}
